/*
 * CanvasGrafo.java
 *
 * Criado em 2 de Junho de 2007, 11:45
 */

package dharsudoku.gui.testes;

import dharsudoku.core.grafo.Grafo;
import dharsudoku.core.vertice.Vertice;
import dharsudoku.core.vertice.VerticeCartesiano;
import dharsudoku.core.vertice.VerticeCoord;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

/**
 * Canvas que mostra um grafo e permite a edição.
 * Suporta exibição e edição de vértices coordenados e
 * suporta apenas vizualização de grafos resultantes de
 * produto cartesiano de grafos com vértices coordenados.
 * @author Rodrigo
 */
public class CanvasGrafo extends Canvas implements MouseListener, MouseMotionListener {
    
    private static final int RAIO = 3;
    
    private Grafo grafo;
    int c;
    private VerticeCoord clicado;
    int px, py;
    
    /**
     * Constroi canvas com grafo vazio
     */
    public CanvasGrafo() {
	super();
	setGrafo(new Grafo());
	c = 1;
    }
    
    /**
     * Constroi canvas com grafo pre estabelecido,
     * deve conter vértices coordenados ou vértices cartesianos
     * de vértices coordenados(somente exibição neste caso)
     * @param grafo Grafo
     */
    public CanvasGrafo(Grafo grafo) {
	super();
	this.setGrafo(grafo);
	c = 1;
    }
    
    
    /**
     * Sobrescreve método paint de java.awt.Canvas
     *@param g Contexto gráfico
     */
    public void paint(Graphics g) {
	
	g.setColor(java.awt.Color.BLACK);
	
	g.drawString(Integer.toString(grafo.getTamanho()), 1, 15);
	
	/* Itera grafo */
	for (java.util.Iterator i = getGrafo().getVertices().iterator(); i.hasNext(); ) {
	    Vertice u = (Vertice)i.next();
	    
	    
	    
	    if (u instanceof VerticeCoord) {
		/* pinta vertice */
		g.drawString(Integer.toString(u.getGrau()), ((VerticeCoord)u).getX()-2, ((VerticeCoord)u).getY()-RAIO);
		g.fillOval(((VerticeCoord)u).getX()-2, ((VerticeCoord)u).getY()-RAIO, RAIO*2, RAIO*2);
	    } else if (u instanceof VerticeCartesiano) {
		/* pinta vertice */
		g.drawString(Integer.toString(u.getGrau()), (((VerticeCoord)((VerticeCartesiano)u).getU()).getX()+((VerticeCoord)((VerticeCartesiano)u).getV()).getX())/2 - RAIO,
			(((VerticeCoord)((VerticeCartesiano)u).getU()).getY()+((VerticeCoord)((VerticeCartesiano)u).getV()).getY())/2 - RAIO);
		g.fillOval((((VerticeCoord)((VerticeCartesiano)u).getU()).getX()+((VerticeCoord)((VerticeCartesiano)u).getV()).getX())/2 - RAIO,
			(((VerticeCoord)((VerticeCartesiano)u).getU()).getY()+((VerticeCoord)((VerticeCartesiano)u).getV()).getY())/2 - RAIO,
			RAIO*2, RAIO*2);
	    }
	    
	    /* Itera adjacentes */
	    for (java.util.Iterator j = u.getAdjacentes().iterator(); j.hasNext(); ) {
		Vertice v = (Vertice)j.next();
		
		/* Desenha linha */
		if (u instanceof VerticeCoord) {
		    
		    g.drawLine(((VerticeCoord)u).getX(), ((VerticeCoord)u).getY(),
			    ((VerticeCoord)v).getX(), ((VerticeCoord)v).getY());
		} else if (u instanceof VerticeCartesiano) {
		    
		    g.drawLine((((VerticeCoord)((VerticeCartesiano)u).getU()).getX()+((VerticeCoord)((VerticeCartesiano)u).getV()).getX())/2,
			    (((VerticeCoord)((VerticeCartesiano)u).getU()).getY()+((VerticeCoord)((VerticeCartesiano)u).getV()).getY())/2,
			    (((VerticeCoord)((VerticeCartesiano)v).getU()).getX()+((VerticeCoord)((VerticeCartesiano)v).getV()).getX())/2,
			    (((VerticeCoord)((VerticeCartesiano)v).getU()).getY()+((VerticeCoord)((VerticeCartesiano)v).getV()).getY())/2);
		}
	    }
	}
	
	if (clicado != null) {
	    g.setColor(java.awt.Color.RED);
	    g.drawLine(clicado.getX(), clicado.getY(), px, py);
	}
    }
    
    /**
     * Limpa gráfico e canvas
     */
    public void clear() {
	grafo.clear();
	this.repaint();
    }
    
    /**
     * Retorna o vértice coordenado(apenas) existente na posição
     * @param px Coordenada x
     * @param py Coordenada y
     * @return Vértice coordenado existente na posição, nulo se não existe
     */
    private VerticeCoord getVertice(int px, int py) {
	/* Itera grafo */
	for (java.util.Iterator i = getGrafo().getVertices().iterator(); i.hasNext(); ) {
	    VerticeCoord u = (VerticeCoord)i.next();
	    
	    if (px >= u.getX()-(RAIO*2) && px <= u.getX()+(RAIO*2) && py >= u.getY()-(RAIO*2) && py <= u.getY()+(RAIO*2)) {
		return u;
	    }
	}
	return null;
    }
    
    /**
     * Evento de mouse: pressionar
     * @param e Objeto descritor do evento
     */
    public void mousePressed(MouseEvent e) {
	if (e.getButton() == e.BUTTON3) {
	    getGrafo().adicionar(new VerticeCoord(c++, e.getX(), e.getY()));
	    this.repaint();
	} else if (e.getButton() == e.BUTTON1) {
	    clicado = getVertice(e.getX(), e.getY());
	    this.px = e.getX();
	    this.py = e.getY();
	}
    }
    
    /**
     * Evento de mouse: soltar
     * @param e Objeto descritor do evento
     */
    public void mouseReleased(MouseEvent e) {
	
	if (e.getButton() == e.BUTTON1 && clicado != null) {
	    
	    VerticeCoord destino = getVertice(e.getX(), e.getY());
	    
	    if (destino != null && destino != clicado) {
		try {
		    getGrafo().adicionarAresta(clicado, destino);
		} catch (Exception ex) {
		    clicado = null;
		    return;
		}
		this.repaint();
	    } else if (destino == null) {
		destino = new VerticeCoord(c++, e.getX(), e.getY());
		getGrafo().adicionar(destino);
		try {
		    getGrafo().adicionarAresta(clicado, destino);
		} catch (Exception ex) {
		    clicado = null;
		    return;
		}
		this.repaint();
	    }
	}
	clicado = null;
    }
    
    /**
     * Retorna grafo do canvas,
     * as alterações não são redesenhadas automaticamente
     * @return Grafo
     */
    public Grafo getGrafo() {
	return grafo;
    }
    
    /**
     * Seta grafo do canvas e redesenha
     * @param grafo Novo grafo
     */
    public void setGrafo(Grafo grafo) {
	this.grafo = grafo;
	this.repaint();
    }
    
    /**
     * Evento de mouse: arrastar
     * @param e Objeto descritor do evento
     */
    public void mouseDragged(MouseEvent e) {
	this.px = e.getX();
	this.py = e.getY();
	this.repaint();
    }
    
    public void mouseMoved(MouseEvent e) {	
    }
    
    public void mouseEntered(MouseEvent e) {
    }
    
    public void mouseExited(MouseEvent e) {
    }
    
    public void mouseClicked(MouseEvent e) {
    }
}
